package cn.hou.socket01._04aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//aio: 服务端
public class Server {
    //线程池
    private ExecutorService executorService;
    //线程组
    private AsynchronousChannelGroup threadGroup;
    //服务器通道
    public AsynchronousServerSocketChannel assc;

    public Server(int port) {
        try {
            executorService = Executors.newCachedThreadPool();//创建线程池
            //创建线程组
            threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
            //创建服务器通道并绑定
            assc = AsynchronousServerSocketChannel.open(threadGroup);
            assc.bind(new InetSocketAddress(port));
            System.out.println("服务器启动.....");
            //进行阻塞,等待接受客户端请求.this代指当前对象，server类的实例对象
            /**
             * 在AIO编程中,发出一个事件（accept read write等）之后要指定事件处理类（回调函数），
             * AIO中的事件处理类是CompletionHandler<V,A>，这个接口定义了两个方法
             * 分别在异步操作成功和失败时被回调
             */
            assc.accept(this, new CompletionHandler<AsynchronousSocketChannel, Server>() {
                //成功回调
                @Override
                public void completed(AsynchronousSocketChannel asc, Server attachment) {
                    //当有下一个客户端接入的时候 直接调用Server的accept方法，这样反复执行下去，保证多个客户端都可以阻塞
                    attachment.assc.accept(attachment, this);//由于是异步,类似于递归,接受后继续阻塞等待下一个客户端
                    read(asc);
                }

                @Override
                public void failed(Throwable exc, Server attachment) {
                    exc.printStackTrace();
                }
            });//此方法为异步
            //不让服务器停止,实际中tomcat一直会运行,所以不用管
            Thread.sleep(Integer.MAX_VALUE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //读取数据
    private void read(final AsynchronousSocketChannel asc) {
        ByteBuffer buf = ByteBuffer.allocate(1024);
        asc.read(buf, buf, new CompletionHandler<Integer, ByteBuffer>() {
            //读取数据成功的回调
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                //进行读取之后,重置标识位
                attachment.flip();
                //获得读取的字节数
                System.out.println("Server -> " + "收到客户端的数据长度为:" + result);
                //获取读取的数据
                String resultData = new String(attachment.array()).trim();
                System.out.println("Server -> " + "收到客户端的数据信息为:" + resultData);
                String response = "服务器响应, 收到了客户端发来的数据: " + resultData;
                write(asc, response);//将数据返回给客户端
            }

            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
            }
        });

    }

    private void write(AsynchronousSocketChannel asc, String response) {
        try {
            ByteBuffer buf = ByteBuffer.allocate(1024);
            buf.put(response.getBytes());
            buf.flip();
            asc.write(buf).get();//get():等待异步执行完成,获取数据
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Server server = new Server(9527);
    }

}
